home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part2 / 17130 < prev    next >
Encoding:
Text File  |  1996-08-05  |  5.1 KB  |  148 lines

  1. Newsgroups: comp.lang.c++
  2. Path: netcom.com!marnold
  3. From: marnold@netcom.com (Matt Arnold)
  4. Subject: [Q] handle/body idiom; downcasting required?
  5. Message-ID: <marnoldDpsMDt.H6B@netcom.com>
  6. Organization: NETCOM On-line Communication Services (408 261-4700 guest)
  7. Distribution: na
  8. Date: Sat, 13 Apr 1996 09:01:05 GMT
  9. Sender: marnold@netcom19.netcom.com
  10.  
  11. Hi,
  12.  
  13. Say I want to define some classes Bar and Foo, whose implemtation varies
  14. according to appropriateness of the implementation for a given condition,
  15. OS platform, or whatever; the point is I want the implementation to vary
  16. independent of the interface's of some classes Bar and Foo, for instance,
  17. that client's will use.  That is, client's will use Bar and Foo unaware
  18. of how they are actually implemented.
  19.  
  20. So, I use the common handle/body design pattern wherein "handle" classes
  21. provide an interface for client's and "body" classes provide an interface
  22. for the handles to implement the required functionality.  Client's call
  23. the handles, unaware of exactly which body services the call.
  24.  
  25. In my example, this would usually by accomplished by creating concrete
  26. handle classes Bar and Foo and abstract body classes AbstractBarImp and
  27. AbstractFooImp.  Bar and Foo contain pointers to their appropriate abstract
  28. implementation class and set them to point to instances of concrete classes,
  29. which provide specific implementations, derived from the abstract bases.
  30.  
  31. The problem arises when one or more of the concrete implementations need
  32. access to another one of the concrete implementations say, to perform some
  33. interaction specific only to the two concrete implementations.  This
  34. interaction is not expressed in the handle or abstract body class interfaces
  35. since it does not belong there.
  36.  
  37. How does one accomplish this using the standard handle/body arrangement?
  38. See the following sample code and final comment in ConcreteFooImp::UseBar(),
  39. which wants to interact with a ConcreteFooImp, but doesn't seem to have the
  40. appropriate types available.
  41.  
  42.  
  43. // generic implementation interfaces ("body" classes)...
  44.  
  45. class AbstractBarImp {
  46.   public:
  47.     virtual void DoSomeFunc() = 0;
  48. };
  49.  
  50. class AbstractFooImp {
  51.   public:
  52.     virtual void DoUseBar(AbstractBarImp* imp) = 0;
  53. };
  54.  
  55.  
  56. // this is what client sees ("handle" classes)
  57.  
  58. class Bar {
  59.   public:
  60.     void SomeFunc() {
  61.       imp->DoSomeFunc();
  62.     }
  63.  
  64.   private:
  65.     AbstractBarImp* imp;
  66. };
  67.  
  68. class Foo {
  69.   public:
  70.     void UseBar(Bar* bar) {
  71.       imp->DoUseBar(bar->imp);
  72.     }
  73.  
  74.   private:
  75.     AbstractFooImp* imp;
  76. };
  77.  
  78.  
  79. // this is what implementor creates (concrete versions of body classes)
  80.  
  81. class ConcreteBarImp: public AbstractBarImp {
  82.   public:
  83.     void DoSomeFunc() {
  84.       // fine; self-contained
  85.     }
  86.  
  87.     void UseMe() {
  88.     }
  89. };
  90.  
  91. class ConcreteFooImp: public AbstractFooImp {
  92.   public:
  93.     void DoUseBar(AbstractBarImp* imp) {
  94.       // problem; how to get access to a ConcreteBarImp* without
  95.       //   downcasting ?
  96.       //
  97.       // for example, how can DoUseBar() call member
  98.       //   ConcreteBarImp()::UseMe() ?
  99.       //
  100.       // (and I don't want to add add virtual AbstractBarImp::UseMe()
  101.       //   because this member may not be appropriate for the other
  102.       //   concrete AbstractBarImp derivations)
  103.     }
  104. };
  105.  
  106.  
  107. Example of where this is a real problem;  Say I used the above Bar/Foo-like
  108. arrangment for Window and Image classes which had specific implementations
  109. for different platforms (WinWindowImp, MacWindowImp, WinImageImp,
  110. MacImageImp, etc.).  And say there existed a member...
  111.  
  112.     Window::DrawImage(Image* image);
  113.  
  114. ...which ends up, in the Windows version, calling...
  115.  
  116.     WinWindowImp::DrawImage(AbstractImageImp* image);
  117.  
  118. Well, WinWindowImp::DrawImage()'s code really wants to deal with a 
  119. WinImageImp*, not an AbstractImageImp*.  In fact, WinWindowImp and 
  120. WinImageImp are probably written with each other in mind and require 
  121. specific interactions not part of (and not appropriate for) the 
  122. AbstractWindowImp and AbstractImageImp interfaces.  I am at a loss right 
  123. now of how to alter the handle/body idiom to make this work cleanly (ie, 
  124. without downcasting).
  125.  
  126.  
  127. My conslusion at the moment seems to be that the drawback to the handle/body
  128. idiom that fact that everthing must be done through abstract interfaces else,
  129. if and when you need specifics, you have to downcast in your concrete
  130. classes.
  131.  
  132. I have the book "Design Patterns" and it covers this idiom, including examples
  133. very similar to this.  However, it appears that the book glosses over details
  134. such as I have described.  The examples in the book seem to assume nothing
  135. more than the concrete implementations being fully self-contained and whose
  136. interactions, if any, are handled only abstractly.  However, this immediately
  137. seems to me like it would be very uncommon.
  138.  
  139. Thanks for any insights,
  140. -------------------------------------------------------------------------
  141. Matt Arnold                       |        | ||| | |||| |  | | || ||
  142. marnold@netcom.com                |        | ||| | |||| |  | | || ||
  143. Boston, MA                        |      0 | ||| | |||| |  | | || ||
  144. 617.389.7384 (h) 617.576.2760 (w) |        | ||| | |||| |  | | || ||
  145. C++, MIDI, Win32/95 developer     |        | ||| 4 3 1   0 8 3 || ||
  146. -------------------------------------------------------------------------
  147.  
  148.